﻿var idCounter = 0;
var enableRatingSubscription = ko.observable(true);

var QkElem = function(type, title, text, post, parent) {
	var _this = this;
	
	var _id = idCounter++;
	
	this.id = ko.computed(function() {
		return _id;
	});
	
	this.parent = ko.computed(function() {
		return parent;
	});
	
	this.type = ko.observable(type);
	this.title = ko.observable(title);
	this.text = ko.observable(text);
	this.childs = ko.observableArray([]);
	this.comments = ko.observableArray([]);
	this.context = ko.observable(null);
	
	this.newCommentText = ko.observable('');
	this.disabled = ko.observable(false);
	
	this.showAllComments = ko.observable(false);
	this.showContext = ko.observable(false);
	
	this.rating = ko.observable('none');
	this.rating.subscribe(function(newRating) { if(enableRatingSubscription()) _this.rate() });
	
	this.pushComment = function(text) {
		if(!post) 
			throw new Error('QkElem.post has no value');
			
		if(!text)
			var text = this.newCommentText();
		
		/*var et = o.dataContext.entityType.bind(o.dataContext);
		var ePost = null, eContent = null, ePostReference = null;*/
		
		var prop = function(e, p) { return e.prop(p).value };
		
		_this.disabled(true);
		disco.Callbacks.batch([
			function(ready) {
				/*o.addEntity(
					{ type: et('Content'), properties: { Text: text, CultureId: 2 /* DE-de *//* }},
					function(ent) { eContent = ent; ready() },
					function(err) { console.error(err) });*/
				disco.web.Requests.addEntity(discoUri + '/Content', {Text: text, CultureId: 2},
					function(ent) { eContent = ent; ready() },
					function(err) { console.error(err) }
				);
			},
			function(ready) {
				/*o.addEntity(*/
				disco.web.Requests.addEntity(discoUri + '/Posts',
					{ContentId: eContent.Id, PostTypeId: 2 /* General */},
					function(ent) { ePost = ent; ready() },
					function(err) { console.error(err) });
			},
			function(ready) {
				/*o.addEntity(*/
				disco.web.Requests.addEntity(discoUri + '/PostReferences',
					{ ReferrerId: ePost.Id, ReferreeId: post.Id, ReferenceTypeId: 2 /* General */ },
					function(ent) { ePostReference = ent; ready() },
					function(err) { console.error(err) });
			}
		],
		function() {
			_this.comments.push(new QkElem('cmt', '', text, ePost, _this));
			_this.newCommentText('');
			_this.disabled(false);
		});
	};
	
	this.rate = function() {
		var score = mapRatingToDisco(_this.rating());
		jData.Ratings.filter("it.PostId == this.PostId && it.UserId == this.UserId", { PostId: post.Id, UserId: 12 }).toArray().then(function(ratings) {
			console.log(ratings);
			if(ratings.length == 0) {
				/*var rating = new Disco.Ontology.Rating({Score: score, PostId: post.Id});
				jData.Ratings.add(rating);
				rating.save();
				jData.saveChanges();*/
				disco.web.Requests.addEntity(discoUri + '/Ratings', { PostId: post.Id, Score: score, UserId: 12 }, 
					function(ent) {
						//setRating(ent);
					},
					function(err) { console.log('err', err) });
			}
			else {
				var rating = ratings[0];
				rating.Score = score;
				rating.save();
			}
		});
	};
	
	this.remove = function() {
		if(!confirm("Wirklich löschen?"))
			return;
		disco.Callbacks.batch([
			function(ready) {
				/*o.getEntitiesByTemplate({ type: o.dataContext.entityType('Post'), properties: { Id: parseInt(post.prop('Id').value), RefersTo: {}, ReferredFrom: {}, Tags: {} }},
					function(ent) {
						post = ent[0];
						ready();
					}
				);**/
				//jData.Posts.filter('it.Id == this.Id', { Id: post.Id }).toArray(function(posts) {
				queryKk(post.Id, true).then(function(posts) {
					post = posts[0];
					ready();
				});
			},
			function(ready) {
				//remove all references
				var batch = post.RefersTo.concat(post.ReferredFrom).map(
					function(ref) {
						return function(r) {
							//o.removeEntity(ref.type, ref.prop('Id').value, r, function(err) { console.error(err); r() });
							console.log(ref.Id);
							disco.web.Requests.removeEntity(discoUri + '/PostReferences(' + ref.Id + ')', r, function(err) { console.error(err); r() });
						}
					}
				);
				disco.Callbacks.batch(batch, ready);
			},
			function(ready) {
				//detach all Tags
				var batch = post.Tags.map(
					function(tag) {
						return function(r) {
							//o.removeConnection(post.type, post.prop('Id').value, post.prop('Tags').property, tag.prop('Id').value, r, function(err) { console.error(err); r() });
							//post.Tags.remove(tag);
							disco.web.Requests.removeEntityConnection(discoUri + '/Posts(' + post.Id + ')', 'Tags(' + tag.Id + ')', r, function(err) { console.error(err); r() });
						}
					}
				);
				disco.Callbacks.batch(batch, ready);
			},
			function(ready) {
				disco.web.Requests.removeEntity(discoUri + '/Posts(' + post.Id + ')', ready, function(err) { console.error(err); r() });
			}
		],
		function() {
			if(parent) parent.removeSubElems(_this);
		});
	};
	
	this.removeSubElems = function(c) {
		_this.comments.remove(c);
		_this.childs.remove(c);
		if(_this.context() == c)
			_this.context(null);
	};
	
	this.dataType = "QkElem";
}

var Tab = function(title) {
	var _this = this;
	
	var _id = idCounter++;
	
	this.id = ko.computed(function() {
		return _id;
	});
	
	this.busy = ko.observable(false);
	
	this.title = ko.observable(title);
	
	this.dataType = "Tab";
}

var KkTab = function(kkObservable) {
	Tab.call(this, 'Konsenskiste');
	var _this = this;
	
	this.kk = kkObservable;
	
	this.dataType = "KkTab";
}

var DocKkTab = function(kkObservable) {
	Tab.call(this, 'Dokumentansicht');
	var _this = this;
	
	this.kk = kkObservable;
	
	this.dataType = 'DocKkTab';
}

var BrowseTab = function() {
	Tab.call(this, 'Suche');
	var _this = this;
	
	this.searchText = ko.observable('');
	
	this.searchMode = ko.observable('kk');
	this.searchButtonDisabled = ko.observable(false);
	
	this.searchResults = ko.observableArray();
	this.searchResultMode = ko.observable();
	
	this.search = function() {
		if(_this.searchMode() == 'kk')
			_this.searchKk();
		else if(_this.searchMode() == 'topic')
			_this.searchTopic();
	}
	this.searchKk = function() {
		_this.searchButtonDisabled(true);
		
		var postRefFilter = jData.PostReferences.filter("it.ReferenceType.Description.Name in ['Part']");
		var postFilter = jData.Posts.filter("it.ReferredFrom.some(this.postRefFilter)", { postRefFilter: postRefFilter }).include("Content");
		
		var promise = postFilter.toArray();
		promise.then(function(posts) {
			_this.searchResults(posts);
			_this.searchResultMode('kk');
			_this.searchButtonDisabled(false);
		});
		
		/*var tpl = {
			type: o.dataContext.entityType('Post'),
			properties: {
				Content: {},
				PostType: { properties: {
					Description: {}
				}},
				ReferredFrom: { properties: {
					ReferenceType: { properties: {
						Description: {}
					}}
				}}
			}
		};
		o.getEntitiesByTemplate(tpl,
			function(ents) {
				var selectedEnts = disco.Collections.where(ents, function(item) {
					var hasPart = disco.Collections.contains(item.prop('ReferredFrom').value, function(reference) {
						return reference.prop('ReferenceType').prop('Description').prop('Name').value == 'Part';
					});
					return hasPart;
				});
			
				//_this.searchResults(selectedEnts.map(function(e) { return e.prop('Content').prop('Title').value }));
				_this.searchResults(selectedEnts);
				_this.searchResultMode('kk');
				_this.searchButtonDisabled(false);
			});*/
	}
	this.searchTopic = function() {
		_this.searchButtonDisabled(true);
		
		var tpl = {
			type: o.dataContext.entityType('Post'),
			properties: {
				Content: {},
				PostType: { properties: {
					Description: {}
				}}
			}
		};
		o.getEntitiesByTemplate(tpl,
			function(ents) {
				var selectedEnts = disco.Collections.where(ents, function(item) {
					console.log(item.prop('PostType').prop('Description').prop('Name').value == 'Topic');
					return item.prop('PostType').prop('Description').prop('Name').value == 'Topic';
				});
			
				//_this.searchResults(selectedEnts.map(function(e) { var cnt = e.prop('Content'); return cnt.prop('Title').value ? (cnt.prop('Title') + '.') : '' + cnt.prop('Text').value }));
				_this.searchResults(selectedEnts);
				_this.searchResultMode('topic');
				_this.searchButtonDisabled(false);
			});
	}
	
	this.resultClicked = function(item) {
		if(_this.searchResultMode() == 'topic')
			selectedTopic(item);
		if(_this.searchResultMode() == 'kk')
			loadKk(item.Id);
	}
	
	this.dataType = 'BrowseTab';
}

var Account = function(userName) {
	var _this = this;
	
	var _id = idCounter++;
	this.id = ko.computed(function() {
		return _id;
	});
	
	this.userName = ko.observable(userName);
};

var ViewModel = function() {
	var _this = this;
	
	var _id = idCounter++;
	
	this.id = ko.computed(function() {
		return _id;
	});
	
	this.kk = ko.observable(null);
	this.selectedTab = ko.observable(null);
	this.tabs = ko.observableArray([]);
	
	this.isAdmin = ko.observable(false);
	
	this.signInName = ko.observable('');
	this.account = ko.observable(null);
	
	this.loadAccount = function() {
		console.log('1');
		$.ajax({
			url: serviceUri + 'ajax/getaccount.php',
			dataType: 'json',
			success: function(data) {
				console.log('2');
				if(data.name && data.name != '')
					_this.account(new Account(data.name));
			},
			cache: false
		});
	};
	
	this.signIn = function() {
		$.ajax({
			url: serviceUri + 'ajax/signin.php',
			data: { name: _this.signInName() },
			dataType: 'json',
			success: function(data) {
				if(!data.success)
					alert('Login fehlgeschlagen. (Serverseitiges Problem)');
				if(data.name && data.name != '')
					_this.account(new Account(data.name));
				else
					_this.account(null);
			},
			cache: false
		})
		.done(function(data) {
			console.log(data);
			if(!data.success)
				alert('Login fehlgeschlagen. (Serverseitiges Problem)');
			if(data.user && data.user != '')
				_this.account(new Account(data.user));
			else
				_this.account(null);
		});
	};
}

function loadKk(postId) {
	vmodel.kk(loadingKk);
	vmodel.selectedTab(tabKk);
	
	queryKk(postId).then(function(posts) {
		var kkData = posts[0];
		
		var kk = new QkElem('kk', kkData.Content.Title, kkData.Content.Text, kkData);
		vmodel.kk(kk);
		
		insertContextAndComments(kk, kkData);
		
		kkData.ReferredFrom.forEach(function(ref) {
			if(ref.ReferenceType.Description.Name != 'Part') return;
			
			var kaData = ref.Referrer;
			var ka = new QkElem('ka', kaData.Content.Title, kaData.Content.Text, kaData, kk);
			kk.childs.push(ka);
			
			insertContextAndComments(ka, kaData);
		});
	});
	/*o.getEntitiesByTemplate(getKkQueryTemplate(postId),
		function(data) {
			console.log('success: ', data);
			
			var kkData = data[0];
			
			var kk = new QkElem('kk', kkData.prop('Content').prop('Title').value, kkData.prop('Content').prop('Text').value, kkData);
			vmodel.kk(kk);
			
			insertContextAndComments(kk, kkData);
			
			var referringToKk = kkData.prop('ReferredFrom').value;
			referringToKk.forEach(function(ref) {
				var refTypeName = ref.prop('ReferenceType').prop('Description').prop('Name').value;
				
				if(refTypeName != 'Part') return;
				
				var kaData = ref.prop('Referrer').value;
				var ka = new QkElem('ka', kaData.prop('Content').prop('Title').value, kaData.prop('Content').prop('Text').value, kaData, kk);
				kk.childs.push(ka);
				
				insertContextAndComments(ka, kaData);
			});
		}
	);*/
}

function insertContextAndComments(qkElem, qkElemData) {
	var elemRefersTo = qkElemData.RefersTo;
	
	//console.log(qkElemData);
	
	if(qkElemData.ReferredFrom)
		qkElemData.ReferredFrom.forEach(function(ref) {
			var refTypeName = ref.ReferenceType.Description.Name;
			
			if(['Part', 'Child', 'Context'].indexOf(refTypeName) != -1)
				return;
			else {
				var cmtData = ref.Referrer;
				var cmt = new QkElem('cmt', cmtData.Content.Title, cmtData.Content.Text, cmtData, qkElem);
				qkElem.comments.push(cmt);
			}
		});
	
	if(qkElemData.RefersTo)
		qkElemData.RefersTo.forEach(function(ref) {
			var refTypeName = ref.ReferenceType.Description.Name;
			
			if(refTypeName == 'Context') {
				var cxtData = ref.Referree;
				var cxt = new QkElem('cxt', cxtData.Content.Title, cxtData.Content.Text, cxtData, qkElem);
				qkElem.context(cxt);
			}
		});
	
	if(qkElemData.Ratings) {
		qkElemData.Ratings.forEach(function(r) { console.log(r.UserId) });
		var rating = disco.Collections.nullableSingle(qkElemData.Ratings, function(rating) { return rating.UserId == 12 });
		enableRatingSubscription(false);
		qkElem.rating(mapRatingFromDisco(rating));
		enableRatingSubscription(true);
		console.log(qkElem.rating());
	}
}

function queryKk(id, extended) {
	var expr = jData.Posts.filter("it.Id == this.Id", { Id: id })
		.include("ReferredFrom.Referrer.Content")
		.include("ReferredFrom.Referrer.Ratings")
		.include("ReferredFrom.Referrer.RefersTo.Referree.Content")
		.include("ReferredFrom.Referrer.RefersTo.Referree.Ratings")
		.include("ReferredFrom.Referrer.RefersTo.ReferenceType.Description")
		.include("ReferredFrom.Referrer.ReferredFrom.Referrer.Content")
		.include("ReferredFrom.Referrer.ReferredFrom.Referrer.Ratings")
		.include("ReferredFrom.Referrer.ReferredFrom.ReferenceType.Description")
		.include("ReferredFrom.ReferenceType.Description")
		.include("RefersTo.Referree")
		.include("RefersTo.Referree.Ratings")
		.include("RefersTo.ReferenceType")
		.include("Content")
		.include("Ratings");
	
	if(extended)
		expr = expr
			.include("Tags");
			
	return expr.toArray();
}

function getKkQueryTemplate(postId) {
	var template = {
		type: o.dataContext.entityType('Post'),
		properties: {
			Id: postId,
			ReferredFrom: { properties: {
				Referrer: { properties: {
					Content: {},
					RefersTo: { properties: {
						Referree: { properties: {
							Content: {}
						}},
						ReferenceType: { properties: {
							Description: {}
						}}
					}},
					ReferredFrom: { properties: {
						Referrer: { properties: {
							Content: {}
						}},
						ReferenceType: { properties: {
							Description: {}
						}}
					}},
				}},
				ReferenceType: { properties: {
					Description: {}
				}}
			}},
			Content: {}
		}
	};
	return template;
}

var ratingStrings = ['strongdislike', 'dislike', 'neutral', 'like', 'stronglike'];

function mapRatingFromDisco(rating) {
	if(rating == null) return 'none';
	var intValue = (Math.round(rating.Score / 3 * 2) + 2);
	return ratingStrings[intValue];
}

function mapRatingToDisco(rating) {
	var intValue = ratingStrings.indexOf(rating);
	return Math.round(intValue / 2 * 3) - 3;
}


vmodel = new ViewModel();

var nullKk = new QkElem('qk-none', 'Keine Konsenskiste ausgewählt', 'Bitte suchen Sie nach einer Konsenskiste!');
var loadingKk = new QkElem('qk-none', 'Laden...', 'Bitte warten!');

var tabKk = new KkTab(vmodel.kk);
var tabDoc = new DocKkTab(vmodel.kk);
var tabHome = new Tab('Übersicht');
var tabHelp = new Tab('?');
var tabBrowse = new BrowseTab();
vmodel.kk(nullKk);
vmodel.tabs([tabHome, tabBrowse, tabKk, tabDoc, tabHelp]);
vmodel.selectedTab(tabHome);

ko.applyBindings(vmodel);

var jData = new Disco.Context(discoUri);
jData.onReady(function() {
	alert('Ready!');
	//vmodel.loadAccount();
	//loadKk(12);
});